package com.music.glide.load.model

import com.music.glide.util.LruCache
import com.music.glide.util.Util

/**
 * 一个键值对存储系统：
 * A 表示“模型”的类型（例如，一个数据标识符）。
 * B 表示与模型相关联的一些可能比较昂贵（如 URL、文件路径等）的对象
 */
class KModelCache<A, B>(private val size: Long = DEFAULT_SIZE) {

    private val cache:LruCache<ModelKey<A>,B>


    fun get(model: A, width: Int, height: Int): B? {
        val modelKey = ModelKey.get(model, width, height)
        val result = cache[modelKey]
        modelKey.release()
        return result
    }

    fun put(model:A,width: Int,height: Int,value:B) {
        cache.put(ModelKey.get(model, width, height), value)
    }

    fun clear() {
        cache.clearMemory()
    }

    init {
        cache = object : LruCache<ModelKey<A>, B>(size) {
            override fun onItemEvicted(key: ModelKey<A>, item: B?) {
                key.release()
            }
        }
    }


    companion object {
        const val DEFAULT_SIZE = 250L
    }

    class ModelKey<A>(private val model: A, private val width: Int, private val height: Int) {

        fun release() {
            synchronized(KEY_QUEUE) {
                KEY_QUEUE.offer(this)
            }
        }

        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as ModelKey<*>

            if (model != other.model) return false
            if (width != other.width) return false
            if (height != other.height) return false

            return true
        }

        override fun hashCode(): Int {
            var result = model?.hashCode() ?: 0
            result = 31 * result + width
            result = 31 * result + height
            return result
        }


        companion object {

            val KEY_QUEUE = Util.createQueue<ModelKey<*>>(0)

            fun <A> get(model: A, width: Int, height: Int): ModelKey<A> {
                var modelKey: ModelKey<A>?
                synchronized(KEY_QUEUE) {
                    modelKey = KEY_QUEUE.poll() as? ModelKey<A>
                }
                if (modelKey == null) {
                    modelKey = ModelKey(model, width, height)
                }
                return modelKey!!
            }
        }
    }
}